package com.netkit;

import com.netkit.event.ChannelEvent;
import com.netkit.event.NetkitChannelEventListener;
import com.netkit.event.SendMessageCompletedListener;
import com.netkit.message.Message;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class NetkitChannelHandler extends SimpleChannelUpstreamHandler {
	private static final Logger LOGGER = LoggerFactory.getLogger(NetkitChannelHandler.class);
	private NetkitContext context;
	private NetkitChannelEventListener channelEventListener;
	private Session session;

	public NetkitChannelHandler(NetkitContext context) {
		this.context = context;
		this.channelEventListener = context.getChannelEventListener();
	}

	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {

		LOGGER.debug("messageReceived:" + e.getMessage());
		if (!(e.getMessage() instanceof Message)) {
			return;
		}

		Message message = (Message) e.getMessage();
		try {
			if (this.channelEventListener != null) {
				ChannelEvent evt = new ChannelEvent(this.context, e.getChannel());
				this.channelEventListener.onMessageReceived(evt, message);
			}
		} catch (Exception ex) {
			LOGGER.warn("handle message reveived event listener exception.", ex);
		}
		
		
		this.session.onRecvMessage(message);
	}

	public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
		if (this.channelEventListener != null) {
			ChannelEvent evt = new ChannelEvent(this.context, e.getChannel());
			this.channelEventListener.onExceptionCaught(evt, e.getCause());
		}
		e.getFuture().cancel();
		Channel channel = e.getChannel();
		LOGGER.warn("channel[" + channel.getId() + "] exception, " + e.getCause().getMessage());
	}

	public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
		super.channelConnected(ctx, e);
		if (this.channelEventListener != null) {
			ChannelEvent evt = new ChannelEvent(this.context, e.getChannel());
			this.channelEventListener.onConnected(evt);
		}

		int sessionSize = this.context.getSessionSize();
		if (sessionSize > this.context.getMaxConnections()) {
			Message message = new Message(0);
			this.session.sendMessage(message).addFutureListener(new SendMessageCompletedListener() {
				public void onComplate(Session session) {
					session.close();
				}
			});
			LOGGER.warn("[WARNING]:The server connections has reached maximum.");
		}
	}

	public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
		super.channelDisconnected(ctx, e);
		if (this.channelEventListener != null) {
			ChannelEvent evt = new ChannelEvent(this.context, e.getChannel());
			this.channelEventListener.onDisconnected(evt);
		}
	}

	public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
		if (this.channelEventListener != null) {
			ChannelEvent evt = new ChannelEvent(this.context, e.getChannel());
			this.channelEventListener.onOpen(evt);
		}
		this.session = this.context.createSession(e.getChannel());
	}

	public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
		super.channelClosed(ctx, e);
		if (this.channelEventListener != null) {
			ChannelEvent evt = new ChannelEvent(this.context, e.getChannel());
			this.channelEventListener.onClosed(evt);
		}
	}
}